package application.mvc.sys.init;

import java.net.URL;
import java.util.LinkedList;
import java.util.List;
import java.util.ResourceBundle;
import org.opencv.videoio.VideoCapture;
import org.opencv.videoio.Videoio;
import com.jfinal.kit.StrKit;
import com.jfinal.log.Log;
import com.jfinal.plugin.activerecord.Db;
import com.sun.jna.NativeLong;
import com.sun.jna.ptr.IntByReference;
import com.zkteco.biometric.FingerprintSensorErrorCode;
import com.zkteco.biometric.FingerprintSensorEx;
import application.common.model.*;
import application.common.render.NET_DVR_DEVICE;
import application.common.ui.AuthorizeDialog;
import application.common.ui.ProgressStage;
import application.common.util.FiltUtil;
import application.common.util.HCNetSDK;
import application.common.util.PwdUtil;
import application.common.util.RouteUtil;
import application.common.util.ShiroUtil;
import application.common.util.HCNetSDK.NET_DVR_DEVICEINFO_V30;
import application.common.util.ZTScannerSDK.ZT_SCA;
import gnu.io.CommPort;
import gnu.io.CommPortIdentifier;
import gnu.io.NoSuchPortException;
import gnu.io.PortInUseException;
import gnu.io.SerialPort;
import gnu.io.UnsupportedCommOperationException;
import javafx.application.Platform;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;

public class InitController implements Initializable {

	protected final Log log = Log.getLog(getClass());

	@FXML
	private Label headerLabel;

	@FXML
	private Label copyrightLabel;

	@FXML
	private ProgressBar initProgressBar;

	@FXML
	private Label messageLabel;

	private long mhDevice = 0;
	private long mhDB = 0;
	private IntByReference nHandle ;
	private VideoCapture capture;

	public void initialize(URL location, ResourceBundle resources) {
		headerLabel.setText(ShiroUtil.getSoftName());
		copyrightLabel.setText(ShiroUtil.getCopyright());
		message("初始化...", true);
		init();
	}

	private void init() {
		Service<Integer> service = new Service<Integer>() {
			@Override
			protected Task<Integer> createTask() {
				return new Task<Integer>() {
					@Override
					protected Integer call() throws Exception {
						message("读取基础配置...", true);
						List<Config> configs = Config.dao.findAll();
						if(configs==null  || configs.size()<=0 ) {
							message("请点击右下角设置按钮注册软件.", false);
							return null;
						}

						if( configs.size()>1) {
							Db.delete(" delete from "+Config.TABLE_NAME);
							Db.delete(" delete from "+Cabinet.TABLE_NAME);
							Db.delete(" delete from "+Board.TABLE_NAME);
							Db.delete(" delete from "+Camera.TABLE_NAME);
							Db.delete(" delete from "+FaultBox.TABLE_NAME);
							Db.delete(" delete from "+Store.TABLE_NAME);
							Db.delete(" delete from "+StoreBox.TABLE_NAME);
							Db.delete(" delete from "+StoreBoxLog.TABLE_NAME);
							Db.delete(" delete from "+StoreLog.TABLE_NAME);
							Db.delete(" delete from "+StoreMap.TABLE_NAME);
							Db.delete(" delete from "+StoreUser.TABLE_NAME);
							Db.delete(" delete from "+User.TABLE_NAME);
							message("请点击右下角设置按钮注册软件.", false);
							return null;
						}
						
						Config config=configs.get(0);
						if(config==null || StrKit.isBlank(config.getId())){
							message("请点击右下角设置按钮注册软件.", false);
							return null;
						}
						
						ShiroUtil.setConfig(config);
						int progressTotal = 5;
						if (StrKit.equals("1", ShiroUtil.getConfig().getIsVideotape())) {
							progressTotal = 6;
						}
						updateProgress(1, progressTotal);
//						Cron4jPlugin cron4jPlugin = new Cron4jPlugin();
//						cron4jPlugin.addTask("* 0 * * *", new ConfigTask());
//						cron4jPlugin.start();
						
						message("初始化化指纹仪...", true);
						if (!ShiroUtil.isDevMode()) {
							if (0 != mhDevice) {
								return null;
							}
							int ret = FingerprintSensorErrorCode.ZKFP_ERR_OK;
							if (FingerprintSensorErrorCode.ZKFP_ERR_OK != FingerprintSensorEx.Init()) {
								message("指纹仪初始化失败...", false);
								return null;
							}
							ret = FingerprintSensorEx.GetDeviceCount();
							if (ret < 0) {
								message("指纹仪连接异常...", false);
								return null;
							}
							if (0 == (mhDevice = FingerprintSensorEx.OpenDevice(0))) {
								message("指纹仪开启异常...", false);
								return null;
							}
							if (0 == (mhDB = FingerprintSensorEx.DBInit())) {
								message("指纹仪算法库初始化失败...", false);
								return null;
							}
							updateProgress(2, progressTotal);
						} else {
							updateProgress(2, progressTotal);
						}

						message("初始化条码扫描仪...", true);
						if (!ShiroUtil.isDevMode()) {
							if(StrKit.isBlank(ShiroUtil.getConfig().getScannerSerialPort()) || StrKit.isBlank(ShiroUtil.getConfig().getScannerModel())) {
								message("请配置扫描仪端口以及型号...", false);
								return null;
							}
							nHandle= new IntByReference();
							nHandle.setValue(0);
							int nRet = ZT_SCA.INSTANCE.ZT_SCA_OpenDevice(
									ShiroUtil.getConfig().getScannerSerialPort(), nHandle,
									Integer.parseInt(ShiroUtil.getConfig().getScannerModel()));
							if (0 != nRet) {
								message("扫描仪始化异常...", false);
								return null;
							}
							if(0 !=  ZT_SCA.INSTANCE.ZT_SCA_Startup(nHandle.getValue())){
								message("二维码扫描仪异常，请联系管理员！", false);
								return null;
							}
							ZT_SCA.INSTANCE.ZT_SCA_Stop(nHandle.getValue());
							updateProgress(3, progressTotal);
						} else {
							updateProgress(3, progressTotal);
						}

						message("初始化人像识别摄像头...", true);
						if (!ShiroUtil.isDevMode()) {
							capture=new VideoCapture(0);  
				            int height = (int)capture.get(Videoio.CAP_PROP_FRAME_HEIGHT);  
				            int width = (int)capture.get(Videoio.CAP_PROP_FRAME_WIDTH);  
				            if(height==0||width==0){  
								message("人像识别摄像头连接异常...", false);
								return null;
					        }
							updateProgress(4, progressTotal);
						} else {
							updateProgress(4, progressTotal);
						}

						message("初始化柜子组...", true);
						if (!ShiroUtil.isDevMode()) {
							List<Cabinet> cabinets = Cabinet.dao.find("SELECT * FROM " + Cabinet.TABLE_NAME);
							if (cabinets == null || cabinets.size() == 0) {
								message("初始化失败，请至少配置一组柜子！", false);
								return null;
							} else {
								boolean isBreak = false;
								for (Cabinet cabinet : cabinets) {
									try {
										CommPortIdentifier portIdentifier = CommPortIdentifier
												.getPortIdentifier("COM" + cabinet.getComPort());
										CommPort commPort = portIdentifier.open("COM" + cabinet.getComPort(), 2000);
										if (commPort instanceof SerialPort) {
											SerialPort serialPort = (SerialPort) commPort;
											try {
												serialPort.setSerialPortParams(cabinet.getBaudRate(),
														SerialPort.DATABITS_8, SerialPort.STOPBITS_1,
														SerialPort.PARITY_NONE);
												serialPort.close();
												commPort.close();
											} catch (UnsupportedCommOperationException e) {
												message(String.format("【%s】配置串口【%s】参数设置失败！", cabinet.getName(),
														cabinet.getComPort()), false);
												isBreak = true;
												break;
											}
										} else {
											message(String.format("【%s】配置串口【%s】并非串口类型！", cabinet.getName(),
													cabinet.getComPort()), false);
											isBreak = true;
											break;
										}
									} catch (NoSuchPortException e1) {
										message(String.format("【%s】配置串口【%s】无效！", cabinet.getName(),
												cabinet.getComPort()), false);
										isBreak = true;
										break;
									} catch (PortInUseException e2) {
										message(String.format("【%s】配置串口【%s】已被占用！", cabinet.getName(),
												cabinet.getComPort()), false);
										isBreak = true;
										break;
									}
								}
								if (isBreak) {
									return null;
								}
								updateProgress(5, progressTotal);
							}
						} else {
							updateProgress(5, progressTotal);
						}

						if (StrKit.equals("1", ShiroUtil.getConfig().getIsVideotape())) {
							message("加载监控摄像头配置...", true);
							if (!ShiroUtil.isDevMode()) {
								
								if(StrKit.isBlank(ShiroUtil.getConfig().getVideotapePath())) {
									message("请配置视频输出路径...", false);
									return null;
								}
								
								List<Camera> cameras = Camera.dao.find("SELECT * FROM " + Camera.TABLE_NAME);
								if (cameras == null || cameras.size() <= 0) {
									message("未检测到监控摄像机配置...", false);
									return null;
								}

								boolean initSuc = HCNetSDK.INSTANCE.NET_DVR_Init();
								if (initSuc != true) {
									message("监控摄像头SDK初始化失败...", false);
									return null;
								}
								FiltUtil.mkdir(String.format("%s\\SdkLog\\", ShiroUtil.getConfig().getVideotapePath()));
								HCNetSDK.INSTANCE.NET_DVR_SetLogToFile(true,String.format("%s\\SdkLog\\", ShiroUtil.getConfig().getVideotapePath()), true);
								boolean isBreak = false;
								List<NET_DVR_DEVICE> NET_DVR_DEVICES=new LinkedList<NET_DVR_DEVICE>();
								for (Camera camera : cameras) {
									if(StrKit.isBlank(camera.getIp())) {
										message(String.format("【%s】未配置IP...", camera.getName()), false);
							        	isBreak=true;
							        	break;
									}
									
									NativeLong lUserID;
									NET_DVR_DEVICEINFO_V30 lpDeviceInfo=new NET_DVR_DEVICEINFO_V30();
								    lUserID=HCNetSDK.INSTANCE.NET_DVR_Login_V30(camera.getIp(), (short) camera.getPort(), camera.getUsername(), camera.getPassword(), lpDeviceInfo);
								    long userID = lUserID.longValue();
							        if (userID == -1)
							        {
							        	message(String.format("IP:【%s】  Port:【%s】 登录失败，错误码【%s】！", camera.getIp(), camera.getPort(), HCNetSDK.INSTANCE.NET_DVR_GetLastError()), false);
							        	isBreak=true;
							        	break;
							        }
							        NET_DVR_DEVICES.add( new NET_DVR_DEVICE(camera,lUserID,lpDeviceInfo));
								}
								if (isBreak) {
									return null;
								}
								ShiroUtil.setCameras(NET_DVR_DEVICES);
								updateProgress(6, progressTotal);
							} else {
								updateProgress(6, progressTotal);
							}
						}
						message("完成...", true);
						destroy();
						Platform.runLater(new Runnable() {
							public void run() {
								RouteUtil.goIndex();
							}
						});
						return null;
					};
				};
			}
		};
		initProgressBar.progressProperty().bind(service.progressProperty());
		service.start();
	}

	public void exit(ActionEvent event) {
		ProgressStage.of(RouteUtil.mainStage, new Task<Void>() {
			@Override
			protected Void call() throws Exception {
				destroy();
				Platform.runLater(new Runnable() {
				    public void run() {
				    	RouteUtil.close();
				    }
				});
				return null;
			}
		},"正在退出软件...").show();
	}

	private void message(final String text, final boolean isOk) {
		Platform.runLater(new Runnable() {
			public void run() {
				if (isOk) {
					messageLabel.setId("message-label");
				} else {
					messageLabel.setId("message-label-error");
				}
				messageLabel.setText(text);
			}
		});
	}

	private void freeSensor() {
		try {
			if (0 != mhDB) {
				FingerprintSensorEx.DBFree(mhDB);
				mhDB = 0;
			}
			if (0 != mhDevice) {
				FingerprintSensorEx.CloseDevice(mhDevice);
				mhDevice = 0;
			}
			FingerprintSensorEx.Terminate();
		} catch (Exception e) {
		}
	}

	public synchronized void destroy() {
		freeSensor();
		if (nHandle!= null) {
			try {
				ZT_SCA.INSTANCE.ZT_SCA_Stop(nHandle.getValue());
				ZT_SCA.INSTANCE.ZT_SCA_CloseDevice(nHandle.getValue());
			}catch (Exception e) {
				e.printStackTrace();
			}
			
		}
		if(capture!=null) {
			capture.release();
		}
	}

	public void setting(ActionEvent event) {
		final AuthorizeDialog authorizeDialog = new AuthorizeDialog(RouteUtil.mainStage);
		authorizeDialog.addListner(new EventHandler<ActionEvent>() {
			public void handle(ActionEvent event) {
				String pwd = authorizeDialog.getPassword();
				if (StrKit.isBlank(pwd)) {
					authorizeDialog.setMsg("密码不可以空！");
					return;
				}
				if (ShiroUtil.getConfig() != null && !StrKit.isBlank(ShiroUtil.getConfig().getPassword())) {
					if (StrKit.equals(PwdUtil.encrypt(pwd), ShiroUtil.getConfig().getPassword())) {
						authorizeDialog.close();
						ProgressStage.of(RouteUtil.mainStage, new Task<Void>() {
							@Override
							protected Void call() throws Exception {
								destroy();
								RouteUtil.goConfig();
								return null;
							}
						},"前往设置页面中...").show();
					} else {
						authorizeDialog.setMsg("密码错误！");
					}
				} else {
					if (StrKit.equals("123456", pwd)) {
						authorizeDialog.close();
						ProgressStage.of(RouteUtil.mainStage, new Task<Void>() {
							@Override
							protected Void call() throws Exception {
								destroy();
								RouteUtil.goConfig();
								return null;
							}
						},"前往设置页面中...").show();
					} else {
						authorizeDialog.setMsg("密码错误！");
					}
				}
			}
		});
		authorizeDialog.addCloseListner(new EventHandler<ActionEvent>() {

			@Override
			public void handle(ActionEvent event) {
				authorizeDialog.close();
			}
		});
	}
}
